﻿using System.Collections;
using System.Data;
using System.Reflection;

namespace MyConvert
{
    public class ModelConvert
    {
        /// <summary>
        /// 数据拷贝
        /// </summary>
        /// <param name="origin">源对象</param>
        /// <param name="target">目标对象</param>
        public static void CopyValue(object origin, object target)
        {
            try
            {
                if (origin == null || target == null)
                {
                    return;
                }
                PropertyInfo[] targetProperties = target.GetType().GetProperties();
                PropertyInfo[] originProperties = origin.GetType().GetProperties();
                foreach (PropertyInfo originProperty in originProperties)
                {
                    foreach (PropertyInfo targetProperty in targetProperties)
                    {
                        if (!string.Equals(originProperty.Name, targetProperty.Name, StringComparison.CurrentCultureIgnoreCase) || !targetProperty.CanWrite)
                        {
                            continue;
                        }
                        object originProValue = originProperty.GetValue(origin, null);
                        if (originProValue == null || targetProperty.PropertyType.IsInstanceOfType(originProValue))
                        {
                            targetProperty.SetValue(target, originProperty.GetValue(origin, null), null);
                        }
                    }
                }
            }
            catch
            {
            }
        }

        /// <summary>
        /// 将DataTable数据源转换成实体类集合
        /// </summary>
        /// <typeparam name="T">返回对象泛型</typeparam>
        /// <param name="dt">表</param>
        /// <returns>List对象</returns>
        public static List<string> ConvertToList<T>(DataTable dt)
        {
            try
            {
                List<string> models = new List<string>();
                if (dt == null || dt.Rows == null || dt.Rows.Count <= 0)
                {
                    return models;
                }
                foreach (DataRow dr in dt.Rows)
                {
                    models.Add(dr[0]?.ToString());
                }
                return models;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 将DataTable数据源转换成实体类集合
        /// </summary>
        /// <typeparam name="T">返回对象泛型</typeparam>
        /// <param name="dt">表</param>
        /// <returns>List对象</returns>
        public static List<T> ConvertToModels<T>(DataTable dt) where T : new()
        {
            try
            {
                List<T> models = new List<T>();
                if (dt == null || dt.Rows == null || dt.Rows.Count <= 0)
                {
                    return models;
                }
                foreach (DataRow dr in dt.Rows)
                {
                    DataColumnCollection dtColumns = dt.Columns;
                    T model = SetValueToModel<T>(dtColumns, dr);
                    models.Add(model);
                }
                return models;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 将DataTable数据源转换成实体类
        /// </summary>
        /// <typeparam name="T">返回对象泛型</typeparam>
        /// <param name="dt">表</param>
        /// <returns>返回对象</returns>
        public static T ConvertToModel<T>(DataTable dt) where T : new()
        {
            try
            {
                T model = new T();
                if (dt == null || dt.Rows == null || dt.Rows.Count <= 0)
                {
                    return model;
                }
                DataRow dr = dt.Rows[0];
                DataColumnCollection dtColumns = dt.Columns;
                model = SetValueToModel<T>(dtColumns, dr);
                return model;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 根据属性名为对象赋值
        /// </summary>
        /// <typeparam name="T">对象泛型</typeparam>
        /// <param name="target">目标对象</param>
        /// <param name="fieldName">属性字段名</param>
        /// <param name="fieldValue">属性字段值</param>
        public static void SetValueForObject<T>(T target, string fieldName, string fieldValue)
        {
            // 获得此模型的公共属性
            PropertyInfo[] propertys = target.GetType().GetProperties();
            foreach (PropertyInfo property in propertys)
            {
                if (fieldName == property.Name)
                {
                    SetValueToObject(target, property, fieldValue);
                    break;
                }
            }
        }

        /// <summary>
        /// 根据实体类获取属性的拼接字段
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <returns>字符串</returns>
        public static string GetField<T>() where T : new()
        {
            try
            {
                string strField = string.Empty;
                T model = new T();
                // 获得此模型的公共属性
                PropertyInfo[] propertys = model.GetType().GetProperties();
                foreach (PropertyInfo property in propertys)
                {
                    strField += $"{property.Name},";
                }
                return strField.Trim(',');
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 集合转DataTable
        /// </summary>
        /// <typeparam name="T">对象</typeparam>
        /// <param name="collection">集合</param>
        /// <returns>DataTable</returns>
        public static DataTable ListToDateTable<T>(IEnumerable<T> collection)
        {
            try
            {
                PropertyInfo[] props = typeof(T).GetProperties();
                DataTable dt = new DataTable();
                dt.Columns.AddRange(props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray());
                if (collection.Count() > 0)
                {
                    for (int i = 0; i < collection.Count(); i++)
                    {
                        ArrayList tempList = new ArrayList();
                        foreach (PropertyInfo pi in props)
                        {
                            object obj = pi.GetValue(collection.ElementAt(i), null);
                            _ = tempList.Add(obj);
                        }
                        object[] array = tempList.ToArray();
                        _ = dt.LoadDataRow(array, true);
                    }
                }
                return dt;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #region 类内部帮助方法

        /// <summary>
        /// 返回一个对象
        /// </summary>
        /// <typeparam name="T">泛型对象</typeparam>
        /// <param name="dtColumns">列值集合</param>
        /// <param name="dr">行值</param>
        /// <returns>对象</returns>
        private static T SetValueToModel<T>(DataColumnCollection dtColumns, DataRow dr) where T : new()
        {
            try
            {
                T model = new T();
                // 获得此模型的公共属性
                PropertyInfo[] propertys = model.GetType().GetProperties();
                foreach (PropertyInfo property in propertys)
                {
                    if (dtColumns.Contains(property.Name))
                    {
                        if (property.CanWrite)
                        {
                            object value = dr[property.Name];
                            if (value != DBNull.Value)
                            {
                                SetValueToObject(model, property, value.ToString());
                            }
                        }
                    }
                }
                return model;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 根据属性类型为属性赋值
        /// </summary>
        /// <param name="target">目标对象</param>
        /// <param name="property">属性</param>
        /// <param name="fieldValue">属性值</param>
        private static void SetValueToObject(object target, PropertyInfo property, string fieldValue)
        {
            if (property.PropertyType == typeof(string))
            {
                property.SetValue(target, fieldValue, null);
            }
            else if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
            {
                _ = DateTime.TryParse(fieldValue, out DateTime value);
                property.SetValue(target, value, null);
            }
            else if (property.PropertyType == typeof(int) || property.PropertyType == typeof(int?))
            {
                _ = int.TryParse(fieldValue, out int value);
                property.SetValue(target, value, null);
            }
            else if (property.PropertyType == typeof(float) || property.PropertyType == typeof(float?))
            {
                _ = float.TryParse(fieldValue, out float value);
                property.SetValue(target, value, null);
            }
            else if (property.PropertyType == typeof(decimal) || property.PropertyType == typeof(decimal?))
            {
                _ = decimal.TryParse(fieldValue, out decimal value);
                property.SetValue(target, value, null);
            }
            else if (property.PropertyType == typeof(double) || property.PropertyType == typeof(double?))
            {
                _ = double.TryParse(fieldValue, out double value);
                property.SetValue(target, value, null);
            }
            else if (property.PropertyType == typeof(long) || property.PropertyType == typeof(long?))
            {
                _ = long.TryParse(fieldValue, out long value);
                property.SetValue(target, value, null);
            }
            else if (property.PropertyType == typeof(short) || property.PropertyType == typeof(short?))
            {
                _ = short.TryParse(fieldValue, out short value);
                property.SetValue(target, value, null);
            }
            else
            {
                property.SetValue(target, fieldValue, null);
            }
        }

        #endregion

    }
}
